from datetime import datetime

from flask_babel import get_locale, _
from flask_login import login_user, current_user, logout_user, login_required
from langdetect import detect, LangDetectException
from werkzeug.urls import url_parse

from app import app, db



# 1  return a simple string
# @app.route('/')
# @app.route('/index')
# def index():
#     return "Hello, World!"

#2 Return complete HTML page from view function;
# @app.route('/')
# @app.route('/index')
# def index():
#     user = {'username': 'Miguel'}  # 2 mock user
#     return '''
# <html>
#     <head>
#         <title>Home Page - Microblog</title>
#     </head>
#     <body>
#         <h1>Hello, ''' + user['username'] + '''!</h1>
#     </body>
# </html>'''

# 2.1 app/routes.py: Use render\_template() function to simplify view function
from flask import render_template, flash, redirect, url_for, request, jsonify
# @app.route('/')
# @app.route('/index')
# def index():
#     user = {'username': 'Miguel'}
# 2.1 render_template--takes a template filename and a variable list of template arguments and returns the same
# template, but with all the placeholders in it replaced with actual values.
#     return render_template('index.html', title='Home', user=user)


# 2.2 conditional statement
from flask import render_template
# @app.route('/')
# @app.route('/index')
# def index():
#     user = {'username': 'Miguel'}
# If the view function forgets to pass a value for the title placeholder variable, then instead of showing an empty title the template will provide a default one.
#     return render_template('index.html', user=user)

# 2.3 loops--fake posts, a list, where each element is a dictionary that has author and body fields.
from app.email import send_password_reset_email
from app.forms import LoginForm, RegistrationForm, EditProfileForm, EmptyForm, PostForm, ResetPasswordRequestForm, \
    ResetPasswordForm
from app.models import User, Post


# 9.1 Post submission form in index view function.
from app.translate import translate


@app.route('/', methods=['GET', 'POST'])
@app.route('/index', methods=['GET', 'POST'])
@login_required
def index():
    form = PostForm()
    if form.validate_on_submit():
# 10.3 Save language for new posts
        try:
            language = detect(form.post.data)
        except LangDetectException:
            language = ''
        post = Post(body=form.post.data, author=current_user, language=language)
        db.session.add(post)
        db.session.commit()
        flash(_('Your post is now live!'))
        return redirect(url_for('index'))
        redirect(url_for('index'))
    # posts = current_user.followed_posts().all()
    # return render_template("index.html", title='Home Page', form=form, posts=posts)
    # 9.4 added pagination to the home view function
    page = request.args.get('page', 1, type=int)
    posts = current_user.followed_posts().paginate(
        page, app.config['POSTS_PER_PAGE'], False)
    # return render_template('index.html', title='Home', form=form,
    #                        posts=posts.items)
    # 9.5 Next and previous page links.
    next_url = url_for('index', page=posts.next_num) \
        if posts.has_next else None
    prev_url = url_for('index', page=posts.prev_num) \
        if posts.has_prev else None
    return render_template('index.html', title='Home', form=form,
                           posts=posts.items, next_url=next_url,
                           prev_url=prev_url)




# 3.4 Form Views, Login view function
# @app.route('/login')
# def login():
#     form = LoginForm()  # instantiate object form LoginForm
#     return render_template('login.html', title='Sign In', form=form)   # send this object ot template


#3.5 Receive form data, receiveing login credentials
# methods argument in the route decorator, tell  Flask which request methods should be accepted.
# @app.route('/login', methods=['GET', 'POST'])
# def login():
#     form = LoginForm()
# form.validate_on_submit method does all the form processing work. when the browser sends the GET/POST request ....
# POST--gather all the data, run all the validators attached to fields, and if everything is all right it will return True
#     if form.validate_on_submit():
# flash function--show message to user, temporary solution, confirms that the application received the credentials.
# it only stords the message
#         flash('Login requested for user {}, remember_me={}'.format(
#             form.username.data, form.remember_me.data))
# redirect function--instructs the client web browser to automatically navigate to a different page, given as an argument.
#         return redirect('/index')
#     return render_template('login.html', title='Sign In', form=form)


# 4.7 Use url_for() function for links, line 95
# @app.route('/login', methods=['GET', 'POST'])
# def login():
#     form = LoginForm()
#     if form.validate_on_submit():
#         flash('Login requested for user {}, remember_me={}'.format(
#             form.username.data, form.remember_me.data))
#         return redirect(url_for('index'))
#     return render_template('login.html', title='Sign In', form=form)


# 5.4 Login view function logic
# @app.route('/login', methods=['GET', 'POST'])
# def login():
#     if current_user.is_authenticated:
#         return redirect(url_for('index'))
#     form = LoginForm()
#     if form.validate_on_submit():
#         user = User.query.filter_by(username=form.username.data).first()
#         if user is None or not user.check_password(form.password.data):
#             flash('Invalid username or password')
#             return redirect(url_for('login'))
#         login_user(user, remember=form.remember_me.data)
#         return redirect(url_for('index'))
#     return render_template('login.html', title='Sign In', form=form)

# 5.7.2 read and process the next query string argument
# 将原来的 return redirect(url_for('index')) 替换为
#          next_page = request.args.get('next')
#         if not next_page or url_parse(next_page).netloc != '':
#             next_page = url_for('index')
#         return redirect(next_page)
@app.route('/login', methods=['GET', 'POST'])
def login():
    if current_user.is_authenticated:
        return redirect(url_for('index'))
    form = LoginForm()
    if form.validate_on_submit():
        user = User.query.filter_by(username=form.username.data).first()
        if user is None or not user.check_password(form.password.data):
            flash('Invalid username or password')
            return redirect(url_for('login'))
        login_user(user, remember=form.remember_me.data)

        next_page = request.args.get('next')
        loc = url_parse(next_page).netloc
        if not next_page or url_parse(next_page).netloc != '':
            next_page = url_for('index')
        return redirect(next_page)
    return render_template('login.html', title='Sign In', form=form)


# 5.5 Logout view function
@app.route('/logout')
def logout():
    logout_user()
    return redirect(url_for('index'))


# 5.9 User registration view function
# The form is handled in the same way as the one for logging in.
# The logic that is done inside the if validate_on_submit() conditional creates a new user with the username,
#   email and password provided, writes it to the database, and then redirects to the login prompt so that the user can log in.
@app.route('/register', methods=['GET', 'POST'])
def register():
    if current_user.is_authenticated:
        return redirect(url_for('index'))
    form = RegistrationForm()
    if form.validate_on_submit():
        user = User(username=form.username.data, email=form.email.data)
        user.set_password(form.password.data)
        db.session.add(user)
        db.session.commit()
        flash('Congratulations, you are now a registered user!')
        return redirect(url_for('login'))
    return render_template('register.html', title='Register', form=form)


# 6.1 User profile view function
# 1. dynamic component in decorator
# 2. load the user from the database using a query by the username--first_or_404(), which works exactly like first()
#  when there are results, but in the case that there are no results automatically sends a 404 error back to the client.
# 3. initialize a fake list of posts for this user
# 4. render a new user.html template to which I pass the user object and the list of posts.
# @app.route('/user/<username>')
# @login_required
# def user(username):
#     user = User.query.filter_by(username=username).first_or_404()
#     posts = [
#         {'author': user, 'body': 'Test post #1'},
#         {'author': user, 'body': 'Test post #2'}
#     ]
#     return render_template('user.html', user=user, posts=posts)

# 8.8 follow and unfollow routes
# @app.route('/user/<username>')
# def user(username):
#     user = User.query.filter_by(username=username).first_or_404()
#     posts = [
#         {'author': user, 'body': 'Test post #1'},
#         {'author': user, 'body': 'Test post #2'}
#     ]
#     form = EmptyForm()
#     return render_template('user.html', user=user, posts=posts, form=form)


# 9.6 Pagination in the user profile view function
#  1. the user.posts relationship is a query that is already set up by SQLAlchemy as a result of the db.relationship() definition
#  in the User model. Note that the pagination links that are generated by the url_for() function need the extra username argument,
#  because they are pointing back at the user profile page, which has this username as a dynamic component of the URL.
@app.route('/user/<username>')
@login_required
def user(username):
    user = User.query.filter_by(username=username).first_or_404()
    page = request.args.get('page', 1, type=int)
    posts = user.posts.order_by(Post.timestamp.desc()).paginate(
        page, app.config['POSTS_PER_PAGE'], False)
    next_url = url_for('user', username=user.username, page=posts.next_num) \
        if posts.has_next else None
    prev_url = url_for('user', username=user.username, page=posts.prev_num) \
        if posts.has_prev else None
    form = EmptyForm()
    return render_template('user.html', user=user, posts=posts.items,
                           next_url=next_url, prev_url=prev_url, form=form)


# 6.5 Record time of last visit
@app.before_request
def before_request():
    if current_user.is_authenticated:
        current_user.last_seen = datetime.utcnow()
        db.session.commit()
    #g.locale = 'zh' if str(get_locale()).startswith('zh') else str(get_locale()) # 14.6 文本翻译视图函数

# 6.6 edit profile editor view function--tie form class and template together
@app.route('/edit_profile', methods=['GET', 'POST'])
@login_required
def edit_profile():
    form = EditProfileForm(current_user.username)   # 7.6 validate username
    if form.validate_on_submit():
        current_user.username = form.username.data
        current_user.about_me = form.about_me.data
        db.session.commit()
        flash('Your changes have been saved.')
        return redirect(url_for('edit_profile'))
    elif request.method == 'GET':
        form.username.data = current_user.username
        form.about_me.data = current_user.about_me
    return render_template('edit_profile.html', title='Edit Profile',
                           form=form)

# 8.8 Follow and unfollow routes
@app.route('/follow/<username>', methods=['POST'])
@login_required
def follow(username):
    form = EmptyForm()
    if form.validate_on_submit():
        user = User.query.filter_by(username=username).first()
        if user is None:
            #flash('User {} not found.'.format(username))
            flash(_('User %(username)s not found.', username=username))
            return redirect(url_for('index'))
        if user == current_user:
            flash('You cannot follow yourself!')
            return redirect(url_for('user', username=username))
        current_user.follow(user)
        db.session.commit()
        #flash('You are following {}!'.format(username))  #13.2 from flask_babel import lazy_gettext as _l
        # flash(_(f'you are following {username} !'))   # 13.2 豆使用Python3中的新语法，尝试看f是否起作用，结果不可以
        flash('You are following %{username}!',username=username)
        return redirect(url_for('user', username=username))
    else:
        return redirect(url_for('index'))


# 8.8 Follow and unfollow routes
@app.route('/unfollow/<username>', methods=['POST'])
@login_required
def unfollow(username):
    form = EmptyForm()
    if form.validate_on_submit():
        user = User.query.filter_by(username=username).first()
        if user is None:
            flash('User {} not found.'.format(username))
            return redirect(url_for('index'))
        if user == current_user:
            flash('You cannot unfollow yourself!')
            return redirect(url_for('user', username=username))
        current_user.unfollow(user)
        db.session.commit()
        flash('You are not following {}.'.format(username))
        return redirect(url_for('user', username=username))
    else:
        return redirect(url_for('index'))

# 9.3 Explore view function--注意呈现模板时没有传入表单
@app.route('/explore')
@login_required
def explore():
    # posts = Post.query.order_by(Post.timestamp.desc()).all()
    # return render_template('index.html', title='Explore', posts=posts)
    # 9.4 added pagination to the explore view functions
    page = request.args.get('page', 1, type=int)
    posts = Post.query.order_by(Post.timestamp.desc()).paginate(
        page, app.config['POSTS_PER_PAGE'], False)
    # return render_template("index.html", title='Explore', posts=posts.items)
    # 9.5 Next and previous page links.
    next_url = url_for('index', page=posts.next_num) \
        if posts.has_next else None
    prev_url = url_for('index', page=posts.prev_num) \
        if posts.has_prev else None
    return render_template('index.html', title='Explore',
                           posts=posts.items, next_url=next_url,
                           prev_url=prev_url)

# 10.4 Reset password request view function
# send_password_reset_email暂时没实现
@app.route('/reset_password_request', methods=['GET', 'POST'])
def reset_password_request():
    if current_user.is_authenticated:
        return redirect(url_for('index'))
    form = ResetPasswordRequestForm()
    if form.validate_on_submit():
        user = User.query.filter_by(email=form.email.data).first()
        if user:
            send_password_reset_email(user)
        flash('Check your email for the instructions to reset your password')
        return redirect(url_for('login'))
    return render_template('reset_password_request.html',
                           title='Reset Password', form=form)

# 10.7 password reset view function
# 1. make sure the user is not logged in
# 2. determine who the user is by invoking the token verification method in the User class
# 3. If the token is invalid I redirect to the home page
# 4. If the token is valid, then I present the user with a second form （ password reset form ), in which the new password is requested
# 5. as a result of a valid form submission, I invoke the set_password() method of User to change the password, and then redirect
#   to the login page
@app.route('/reset_password/<token>', methods=['GET', 'POST'])
def reset_password(token):
    if current_user.is_authenticated:
        return redirect(url_for('index'))
    user = User.verify_reset_password_token(token)
    if not user:
        return redirect(url_for('index'))
    form = ResetPasswordForm()
    if form.validate_on_submit():
        user.set_password(form.password.data)
        db.session.commit()
        flash('Your password has been reset.')
        return redirect(url_for('login'))
    return render_template('reset_password.html', form=form)


# 14.6 文本翻译视图函数
@app.route('/translate', methods=['POST'])
@login_required
def translate_text():
    return jsonify({'text': translate(request.form['text'],request.form['source_language'],request.form['dest_language'])})

